#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <errno.h>
#include <signal.h>
#include "atomic.h"

//测试程序来自:http://www.alexonlinux.com/multithreaded-simple-data-type-access-and-atomic-variables/comment-page-1#comment-27528
//编译命令:gcc test02.c -o test02 -D_GNU_SOURCE -lpthread
//gcc test02.c -o test02 -lpthread -D_GNU_SOURCE
#define INC_TO 1000000

int global_int = 0;
atomic_t g = 0;
pid_t gettid(void)
{
  return syscall(__NR_gettid);
}

void *thread_routine(void *arg)
{
  int i;
  int proc_num = (int)(long)arg;
  cpu_set_t set;
  
  CPU_ZERO(&set);
  CPU_SET(proc_num,&set);
  
  if(sched_setaffinity(gettid(),sizeof(cpu_set_t),&set))
  {
    perror("sched_setaffinity");
    return NULL;
  }
  for(i=0;i<INC_TO;i++)
  {
        global_int++;
    //    __sync_fetch_and_add(&global_int,1);
    fetch_and_add(&g,1);
 // 	g++;
  }

  return NULL;
}

int dec_and_test(atomic_t *value)
{
  int c;
  asm volatile("lock;decl %0;sete %1":"+m"(value),"=qm"(c):"m"(value):"memory");
  return c;
}

int main()
{
  int procs = 0;
  int i;
  pthread_t *thrs;
  //Getting number of CPUs
  procs = (int)sysconf(_SC_NPROCESSORS_ONLN);
  if(procs <0)
  {
    perror("sysconf");
    return -1;
  }
  thrs = malloc(sizeof(pthread_t)*procs);
  if(thrs == NULL)
  {
    perror("malloc");
    return -1;
  }
  
  printf("Starting %d threads ...\n",procs);
  for(i=0;i<procs;i++)
  {
    if(pthread_create(&thrs[i],NULL,thread_routine,(void *)(long)i))
    {
      perror("pthread_create");
      procs = i;
      break;
    }
    
  }

  for(i=0;i<procs;i++)
    pthread_join(thrs[i],NULL);
  free(thrs);
  printf("After doing all the math,global_int value is:%d,g:%d\n",global_int,g);
  printf("Expected value is:%d\n",INC_TO*procs);
  return 0;
}


int main1()
{
  atomic_t v;
  fetch_and_add(&v,1);
  if(sub_and_test(&v,1))
  {
    printf("atomic key is 0\n");
  }
  else
  {
    printf("atomic key isn't 0:%d\n",v);
  }
  
  
  return 0;
}
